// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现大小。

package types2

// Sizes定义了包的大小调整函数。
type Sizes interface {
	// Alignof返回T类型变量的对齐方式。
	// Alignof必须实现规范要求的对齐保证。
	Alignof(T Type) int64

	// Offsetsof返回给定结构字段的偏移量，以字节为单位。
	// Offsetsof必须实现规范要求的偏移保证。
	Offsetsof(fields []*Var) []int64

	// Sizeof返回T类型变量的大小。
	// Sizeof必须实现规范要求的大小保证。
	Sizeof(T Type) int64
}

// StdSizes是创建常用大小的方便类型。
// 它做出以下简化假设：
// 
// -显式大小的基本类型（int16等）的大小是
// 指定的大小。
// /-字符串和接口的大小为2*WordSize。
// /-切片大小为3*WordSize。
// -由n个元素组成的数组的大小对应于该数组元素类型的n个连续字段的结构。
// -结构的大小是最后一个字段加上该字段大小的偏移量。与所有元素类型一样，如果在数组中使用结构
// 其大小必须首先与
// 结构对齐的倍数对齐。
// /-所有其他类型都有大小字大小。wen jian defg
// 类型自然与最大对齐MaxAlign对齐。
// 
// /*标准尺寸。
// 
type StdSizes struct {
	WordSize int64 // 以字节为单位的字大小-必须大于等于4（32位）
	MaxAlign int64 // 以字节为单位的最大对齐方式-必须大于等于1 
}

func (s *StdSizes) Alignof(T Type) int64 {
	// 对于数组和结构，对齐方式分别按照元素和字段对齐方式的
	// 定义。
	switch t := under(T).(type) {
	case *Array:
		// spec:“对于数组类型的变量x：unsafe.Alignof（x）
		// 与unsafe.Alignof（x[0]）相同，但至少为1。”
		return s.Alignof(t.elem)
	case *Struct:
		// spec:“对于结构类型为x的变量：unsafe.Alignof（x）
		// 是unsafe.Alignof（x.f）中最大的值。对于每个
		// 字段，但至少为1。”
		max := int64(1)
		for _, f := range t.fields {
			if a := s.Alignof(f.typ); a > max {
				max = a
			}
		}
		return max
	case *Slice, *Interface:
		// 多字数据结构是有效的结构
		// 其中每个元素都有大小字大小。
		// 类型参数导致可变大小/对齐；
		// StdSizes。不会为他们打电话。
		assert(!isTypeParam(T))
		return s.WordSize
	case *Basic:
		// 字符串就像片和接口。
		if t.Info()&IsString != 0 {
			return s.WordSize
		}
	case *TypeParam, *Union:
		unreachable()
	}
	a := s.Sizeof(T) // 可能是0 
	// 规范：“对于任何类型的变量x：不安全。Alignof（x）至少为1。”
	if a < 1 {
		return 1
	}
	// 复数{64128}像[2]float{32,64}一样排列。
	if isComplex(T) {
		a /= 2
	}
	if a > s.MaxAlign {
		return s.MaxAlign
	}
	return a
}

func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
	offsets := make([]int64, len(fields))
	var o int64
	for i, f := range fields {
		a := s.Alignof(f.typ)
		o = align(o, a)
		offsets[i] = o
		o += s.Sizeof(f.typ)
	}
	return offsets
}

var basicSizes = [...]byte{
	Bool:       1,
	Int8:       1,
	Int16:      2,
	Int32:      4,
	Int64:      8,
	Uint8:      1,
	Uint16:     2,
	Uint32:     4,
	Uint64:     8,
	Float32:    4,
	Float64:    8,
	Complex64:  8,
	Complex128: 16,
}

func (s *StdSizes) Sizeof(T Type) int64 {
	switch t := under(T).(type) {
	case *Basic:
		assert(isTyped(T))
		k := t.kind
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		if k == String {
			return s.WordSize * 2
		}
	case *Array:
		n := t.len
		if n <= 0 {
			return 0
		}
		// n>0 
		a := s.Alignof(t.elem)
		z := s.Sizeof(t.elem)
		return align(z, a)*(n-1) + z
	case *Slice:
		return s.WordSize * 3
	case *Struct:
		n := t.NumFields()
		if n == 0 {
			return 0
		}
		offsets := s.Offsetsof(t.fields)
		return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
	case *Interface:
		// 类型参数导致大小/对齐不一；
		// 标准尺寸。Sizeof不会为他们而被要求。
		assert(!isTypeParam(T))
		return s.WordSize * 2
	case *TypeParam, *Union:
		unreachable()
	}
	return s.WordSize // 获取所有
}

// 通用体系结构字号和对齐
var gcArchSizes = map[string]*StdSizes{
	"386":      {4, 4},
	"arm":      {4, 4},
	"arm64":    {8, 8},
	"amd64":    {8, 8},
	"amd64p32": {4, 8},
	"mips":     {4, 4},
	"mipsle":   {4, 4},
	"mips64":   {8, 8},
	"mips64le": {8, 8},
	"ppc64":    {8, 8},
	"ppc64le":  {8, 8},
	"riscv64":  {8, 8},
	"s390x":    {8, 8},
	"sparc64":  {8, 8},
	"wasm":     {8, 8},
	// 在此处添加更多体系结构时，
	// 更新以下sizes的文档字符串。
}

// SizesFor返回编译器用于体系结构的大小。
// 如果编译器/体系结构对未知，则结果为零。
// 
// 编译器“gc”支持的体系结构：
// “386”、“arm”、“arm64”、“amd64”、“amd64”、“amd64p32”、“mips”、“mipsle”、
// “mips64”、“mips64le”、“ppc64”、“ppc64le”、“riscv64”、“s390x”、“sparc64”、“wasm”。
func SizesFor(compiler, arch string) Sizes {
	var m map[string]*StdSizes
	switch compiler {
	case "gc":
		m = gcArchSizes
	case "gccgo":
		m = gccgoArchSizes
	default:
		return nil
	}
	s, ok := m[arch]
	if !ok {
		return nil
	}
	return s
}

// 如果配置，则使用stdSizes。大小=零。
var stdSizes = SizesFor("gc", "amd64")

func (conf *Config) alignof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if a := s.Alignof(T); a >= 1 {
			return a
		}
		panic("Config.Sizes.Alignof returned an alignment < 1")
	}
	return stdSizes.Alignof(T)
}

func (conf *Config) offsetsof(T *Struct) []int64 {
	var offsets []int64
	if T.NumFields() > 0 {
		// 按需计算偏移量
		if s := conf.Sizes; s != nil {
			offsets = s.Offsetsof(T.fields)
			// 健全性检查
			if len(offsets) != T.NumFields() {
				panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
			}
			for _, o := range offsets {
				if o < 0 {
					panic("Config.Sizes.Offsetsof returned an offset < 0")
				}
			}
		} else {
			offsets = stdSizes.Offsetsof(T.fields)
		}
	}
	return offsets
}

// offsetof返回通过
// 指定的字段相对于类型的索引序列的偏移量。所有嵌入字段
// 必须是结构（而不是指向结构的指针）。
func (conf *Config) offsetof(typ Type, index []int) int64 {
	var o int64
	for _, i := range index {
		s := under(typ).(*Struct)
		o += conf.offsetsof(s)[i]
		typ = s.fields[i].typ
	}
	return o
}

func (conf *Config) sizeof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if z := s.Sizeof(T); z >= 0 {
			return z
		}
		panic("Config.Sizes.Sizeof returned a size < 0")
	}
	return stdSizes.Sizeof(T)
}

// align返回最小的y>=x，这样y%a==0。
func align(x, a int64) int64 {
	y := x + a - 1
	return y - y%a
}
